home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Deutsche Edition 1
/
Deutsche Edition 1.iso
/
amok
/
amok_lha
/
amok77.lha
/
Funktionen
/
Funktionen.mod
< prev
next >
Wrap
Text File
|
1993-08-15
|
14KB
|
418 lines
(****************************************************************************
:Program. Funktionen.mod
:Contents. floating-point arithmetic compiler
:Author. Richard Günther [gvm]
:Address. HeilbronnerStr.267, 7410 Reutlingen
:Phone. 07121/66432
:Copyright. Public Domain
:Language. Oberon
:Translator. AmigaOberon v2.14d
:Imports. ExecLists [gvm]
:History. V1.0 [gvm] 15-May-92 first implementation
:History. V1.1 [gvm] 05-July-92 cosmetic changes
:Bugs. does not support Commodores MathIEEESing-Libs because of
:Bugs. AmigaOberon not supporting them (number format problems)
****************************************************************************)
(* Compiler Grammar:
Ausdruck = Summe.
Summe = Produkt {("+"|"-") Produkt}.
Produkt = Potenz {("*"|"/") Potenz}.
Potenz = Faktor {"^" Faktor}.
Faktor = ["+"|"-"](("(" Summe ")")|
(Funktion "(" Summe ")")|
Variable | Zahl | "pi" | "e").
Funktion = "SIN" | "COS" | "TAN" |....
Zahl = Ziffern["." Ziffern]["E"["+"|"-"] Ziffern].
Ziffern = Ziffer {Ziffer}.
Variable = CHAR. *)
MODULE Funktionen ;
IMPORT S : SYSTEM,
O : OberonLib,
E : Exec,
EL : ExecLists,
ST : Strings,
RC : RealConversions,
LRC : LongRealConversions ;
TYPE FunktionPtr = POINTER TO Funktion ;
Funktion = RECORD (EL.Node)
transLib : E.LibraryPtr ;
basLib : E.LibraryPtr ;
code : LONGINT ; (* code-speicher *)
END ;
Func = STRUCT
name : ARRAY 6 OF CHAR ;
offs : INTEGER ;
base : INTEGER ;
END ;
FArrayTyp = ARRAY 15 OF Func ;
CONST bas=0 ; trans=1 ;
CONST FArray = FArrayTyp("ABS",-54,bas, "ACOS",-120,trans,
"ASIN",-114,trans, "ATAN",-30,trans,
"COS",-42,trans, "COSH",-66,trans,
"EXP",-78,trans, "LN",-84,trans,
"LOG",-126,trans, "SIN",-36,trans,
"SINH",-60,trans, "SQRT",-96,trans,
"TAN",-48,trans, "TANH",-72,trans,
"",0,0
) ;
(* Hier einige Standart-ProzedurTypen: *)
TYPE FuncX* = PROCEDURE(x : REAL): REAL ;
FuncXL* = PROCEDURE(x : LONGREAL): LONGREAL ;
FuncXY* = PROCEDURE(x,y : REAL): REAL ;
FuncXYL* = PROCEDURE(x,y : LONGREAL): LONGREAL ;
(* eins von diesen bitte bei Compile.precision angeben: *)
CONST ffp*=0 ; single*=ffp ; double*=2 ;
(* Achtung !: OBERON unterstützt das SingleIEEE-Format nicht! *)
(* Deshalb ist single hier gleich ffp! *)
VAR funcList : EL.List ;
pi,e : REAL ;
piL,eL : LONGREAL ;
PROCEDURE Compile*( source : ARRAY OF CHAR ;
vars : ARRAY OF CHAR ; (* z.B. "xy" *)
precision : INTEGER ;
VAR proc : ARRAY OF BYTE ; (* TermProzedur *)
VAR errpos : INTEGER): BOOLEAN ;
VAR func : FunktionPtr ;
len : INTEGER ;
code : BOOLEAN ;
offs : INTEGER ;
pos : INTEGER ;
size : INTEGER ;
numVars : INTEGER ;
lastPushed : BOOLEAN ;
basInA6 : BOOLEAN ;
aPtr : POINTER TO S.ADDRESS ;
PROCEDURE Put2(w : INTEGER) ;
VAR iPtr : POINTER TO INTEGER ;
BEGIN
IF code THEN
iPtr:=S.ADR(func.code) ; iPtr:=S.VAL(S.ADDRESS,S.VAL(LONGINT,iPtr)+offs) ;
iPtr^:=w ;
END ;
INC(offs,2) ;
END Put2 ;
PROCEDURE Put4(l : LONGINT) ;
VAR iPtr : POINTER TO LONGINT ;
BEGIN
IF code THEN
iPtr:=S.ADR(func.code) ; iPtr:=S.VAL(S.ADDRESS,S.VAL(LONGINT,iPtr)+offs) ;
iPtr^:=l ;
END ;
INC(offs,4) ;
END Put4 ;
PROCEDURE Push ;
BEGIN
IF precision=double THEN Put4(048E7C000H) (* MOVEM.L D0-D1,-(SP) *)
ELSE Put2(02F00H) ; (* MOVE.L D0,-(SP) *)
END ;
lastPushed:=TRUE ;
END Push ;
PROCEDURE Pea(data : ARRAY OF BYTE) ;
VAR ptr : POINTER TO LONGINT ;
len : INTEGER ;
BEGIN
len:=LEN(data) ; ptr:=S.VAL(S.ADDRESS,S.VAL(LONGINT,S.ADR(data))+len-4) ;
WHILE len>0 DO
IF ptr^=LONG(SHORT(ptr^)) THEN Put2(04878H) ; Put2(SHORT(ptr^)) ; (* PEA data.W *)
ELSE Put2(04879H) ; Put4(ptr^) ; (* PEA data.L *)
END ;
DEC(len,4) ; ptr:=S.VAL(S.ADDRESS,S.VAL(LONGINT,ptr)-4) ;
END ;
lastPushed:=FALSE ;
END Pea ;
PROCEDURE Pop ;
BEGIN
IF lastPushed THEN
IF precision=double THEN DEC(offs,4)
ELSE DEC(offs,2)
END ;
lastPushed:=FALSE ;
ELSE
IF precision=double THEN Put4(04CDF0003H) (* MOVEM.L (SP)+,D0-D1 *)
ELSE Put2(0201FH) (* MOVE.L (SP)+,D0 *)
END ;
END ;
END Pop ;
PROCEDURE Pop2 ;
BEGIN
IF precision=double THEN
IF lastPushed THEN DEC(offs,4) ; Put4(024002601H) (* MOVE.L D0/D1,D2/D3 *)
ELSE Put4(04CDF000CH) ; (* MOVEM.L (SP)+,D2-D3 *)
END ;
Put4(04CDF0003H) (* MOVEM.L (SP)+,D0-D1 *)
ELSE
IF lastPushed THEN DEC(offs,2) ; Put2(02200H) (* MOVE.L D0,D1 *)
ELSE Put2(0221FH) ; (* MOVE.L (SP)+,D1 *)
END ;
Put2(0201FH) (* MOVE.L (SP)+,D0 *)
END ;
lastPushed:=FALSE ;
END Pop2 ;
PROCEDURE Load(varNo : INTEGER) ;
VAR of : INTEGER ;
BEGIN
of:=varNo*4 ;
IF precision=double THEN Put2(02F2DH) ; Put2(2*of+4) ;
Put2(02F2DH) ; Put2(2*of) ;
ELSE Put2(02F2DH) ; Put2(of) ; (* MOVE.L of(A5),-(SP) *)
END ;
IF of=0 THEN DEC(offs,4) ; Put2(02F15H) END ; (* MOVE.L (A5),-(SP) *)
lastPushed:=FALSE ;
END Load ;
PROCEDURE Call(base,offs : INTEGER) ;
BEGIN
IF ((base=bas) AND NOT basInA6) OR ((base=trans) AND basInA6) THEN
Put2(0C94EU) ; basInA6:=NOT basInA6 ;
END ;
Put2(04EAEH) ; Put2(offs) ; (* JSR offs(A6) *)
END Call ;
PROCEDURE Fehler ;
BEGIN
IF errpos=-1 THEN errpos:=pos ; pos:=256 END ;
END Fehler ;
PROCEDURE Match(c : CHAR):BOOLEAN ;
BEGIN
IF source[pos]=c THEN INC(pos) ; RETURN FALSE
ELSE Fehler ; RETURN TRUE
END ;
END Match ;
PROCEDURE SkipBlanks ;
BEGIN
WHILE (pos<=len) AND (source[pos]=" ") DO INC(pos) END ;
END SkipBlanks ;
PROCEDURE ^Summe(): BOOLEAN ;
PROCEDURE ReadZiffern():BOOLEAN ;
BEGIN
IF (pos>len) OR ((source[pos]<"0") OR (source[pos]>"9")) THEN
Fehler ; RETURN TRUE END ;
WHILE (pos<=len) AND ((source[pos]>="0") AND (source[pos]<="9")) DO
INC(pos) END ;
RETURN FALSE ;
END ReadZiffern ;
PROCEDURE Zahl(negativ: BOOLEAN): BOOLEAN ;
VAR start: INTEGER ;
buf : ARRAY 32 OF CHAR ;
lr: LONGREAL ; r: REAL ;
BEGIN
start:=pos ;
IF ReadZiffern() THEN RETURN TRUE END ;
IF (pos<=len) AND (source[pos]=".") THEN
INC(pos) ; IF ReadZiffern() THEN RETURN TRUE END ;
END ;
IF (pos<=len) AND (source[pos]="E") THEN
INC(pos) ;
IF (pos<=len) AND ((source[pos]="+") OR (source[pos]="-")) THEN
INC(pos) ; END ;
IF ReadZiffern() THEN RETURN TRUE END ;
END ;
IF negativ THEN DEC(start) END ;
ST.Cut(source,start,pos-start,buf) ;
IF precision=double THEN
IF NOT LRC.StringToReal(buf,lr) THEN RETURN TRUE END ; Pea(lr) ;
ELSE
IF NOT RC.StringToReal(buf,r) THEN RETURN TRUE END ; Pea(r) ;
END ;
RETURN FALSE
END Zahl ;
PROCEDURE Faktor():BOOLEAN ;
VAR negieren : BOOLEAN ;
token : ARRAY 8 OF CHAR ;
tpos : INTEGER ;
BEGIN
SkipBlanks ;
negieren:=(pos<=len) AND (source[pos]="-") ;
IF (pos<=len) AND ((source[pos]="+") OR (source[pos]="-")) THEN
INC(pos)
END ;
IF (pos<=len) THEN
CASE source[pos] OF
"0".."9": IF Zahl(negieren) THEN RETURN TRUE END ;
negieren:=FALSE |
"(": INC(pos) ;
IF Summe() OR Match(")") THEN RETURN TRUE END |
ELSE
tpos:=0 ;
WHILE (source[pos]>="A") AND (source[pos]<="Z") DO
token[tpos]:=source[pos] ; INC(tpos) ; INC(pos) ;
END ;
token[tpos]:=CHR(0) ;
tpos:=0 ;
LOOP
WHILE FArray[tpos].name#"" DO
IF token=FArray[tpos].name THEN
IF Match("(") OR Summe() OR Match(")") THEN RETURN TRUE END ;
Pop ; Call(FArray[tpos].base,FArray[tpos].offs) ; Push ;
EXIT ;
END ;
INC(tpos) ;
END ;
IF token="PI" THEN
IF precision=double THEN Pea(piL)
ELSE Pea(pi)
END ;
ELSIF token="E" THEN
IF precision=double THEN Pea(eL)
ELSE Pea(e)
END ;
ELSIF token[1]=CHR(0) THEN
tpos:=0 ;
WHILE tpos#numVars DO
IF vars[tpos]=token[0] THEN
Load(numVars-tpos-1) ; (* umgekehrte Reihenfolge ! *)
EXIT ;
END ;
INC(tpos) ;
END ;
Fehler ;
ELSE Fehler ; RETURN TRUE
END ;
EXIT ;
END ;
END ;
END ;
IF negieren THEN
Pop ; Call(bas,-60) ; Push ; (* Neg *)
END ;
SkipBlanks ;
RETURN FALSE ;
END Faktor ;
PROCEDURE Potenz(): BOOLEAN ;
BEGIN
IF Faktor() THEN RETURN TRUE END ;
WHILE (pos<=len) AND (source[pos]="^") DO
INC(pos) ;
IF Faktor() THEN RETURN TRUE END ;
Pop2 ; Call(trans,-90) ; Push ; (* Pow *)
END ;
RETURN FALSE ;
END Potenz ;
PROCEDURE Produkt(): BOOLEAN ;
VAR ch : CHAR ;
BEGIN
IF Potenz() THEN RETURN TRUE END ;
WHILE (pos<=len) AND ((source[pos]="*") OR (source[pos]="/")) DO
ch:=source[pos] ; INC(pos) ;
IF Potenz() THEN RETURN TRUE END ;
Pop2 ;
IF ch="*" THEN Call(bas,-78) (* Mul *)
ELSE Call(bas,-84) (* Div *)
END ;
Push ;
END ;
RETURN FALSE ;
END Produkt ;
PROCEDURE Summe(): BOOLEAN ;
VAR ch : CHAR ;
BEGIN
IF Produkt() THEN RETURN TRUE END ;
WHILE (pos<=len) AND ((source[pos]="+") OR (source[pos]="-")) DO
ch:=source[pos] ; INC(pos) ;
IF Produkt() THEN RETURN TRUE END ;
Pop2 ;
IF ch="+" THEN Call(bas,-66) (* Add *)
ELSE Call(bas,-72) (* Sub *)
END ;
Push ;
END ;
END Summe ;
PROCEDURE Ausdruck(): BOOLEAN ;
BEGIN
pos:=0 ; errpos:=-1 ; lastPushed:=FALSE ; basInA6:=TRUE ;
ST.Upper(vars) ; numVars:=ST.Length(vars) ;
Put4(048E7300EH) ; (* movem.l d2-d3/a4-6,-(sp) *)
Put4(04BEF0018H) ; (* lea 24(a7),a5 *)
Put2(02C7AH) ; Put2(-4-offs) ; (* move.l -4(func.code),A6 *)
Put2(0287AH) ; Put2(-8-offs) ; (* move.l -8(func.code),A4 *)
IF Summe() OR
(offs=16) THEN RETURN TRUE END ; (* "leerer" code ? *)
Pop ; (* Ergebnis in D0/D1 *)
Put4(04CDF700CH) ; (* movem.l (sp)+,d2-d3/a4-6 *)
Put2(0205FH) ; (* move.l (sp)+,a0 rts-adr *)
IF numVars#0 THEN
Put2(04FEFH) ; (* lea numvars*prec(a7),a7 *)
IF precision=double THEN Put2(numVars*8)
ELSE Put2(numVars*4)
END ;
END ;
Put2(04ED0H) ; (* jmp (a0) *)
RETURN FALSE ;
END Ausdruck ;
BEGIN
ST.Upper(source) ; len:=ST.Length(source) ;
code:=FALSE ; offs:=0 ;
IF (len=0) OR Ausdruck() THEN RETURN FALSE END ;
size:=offs+S.SIZE(Funktion) ; O.New(func,size) ;
IF func=NIL THEN errpos:=-2 ; RETURN FALSE END ;
S.INIT(func) ;
CASE precision OF
ffp : func.basLib:=E.OpenLibrary("mathffp.library",0) ;
func.transLib:=E.OpenLibrary("mathtrans.library",0) |
(* single : func.basLib:=E.OpenLibrary("mathieeesingbas.library",0) ;
func.transLib:=E.OpenLibrary("mathieeesingtrans.library",0) | *)
double : func.basLib:=E.OpenLibrary("mathieeedoubbas.library",0) ;
func.transLib:=E.OpenLibrary("mathieeedoubtrans.library",0) |
END ;
IF (func.basLib=NIL) OR (func.transLib=NIL) THEN
IF func.transLib#NIL THEN E.CloseLibrary(func.transLib) ;
ELSIF func.basLib#NIL THEN E.CloseLibrary(func.basLib) ;
END ;
DISPOSE(func) ; errpos:=-2 ;
RETURN FALSE ;
END ;
code:=TRUE ; offs:=0 ;
IF Ausdruck() THEN END ;
EL.AddHead(funcList,func) ;
aPtr:=S.ADR(proc) ; aPtr^:=S.ADR(func.code) ;
RETURN TRUE ;
END Compile ;
(* unschön, aber praktisch (keine Typenumwandlung nötig) *)
PROCEDURE Dispose*{"Funktionen.Dis"}(VAR func{8} : ARRAY OF BYTE) ;
PROCEDURE Dis*(VAR func{8} : FunktionPtr) ; (* eigentlich Funktion.code *)
BEGIN
func:=S.VAL(FunktionPtr,S.VAL(LONGINT,func)-S.SIZE(Funktion)+8) ;
E.CloseLibrary(func.transLib) ;
E.CloseLibrary(func.basLib) ;
EL.Remove(func) ;
DISPOSE(func) ;
END Dis ;
PROCEDURE CloseDispose*(func : EL.NodePtr) ; (* nur wegen VAR-Parameter nötig *)
BEGIN
func:=S.ADR(func(Funktion).code) ;
Dispose(func) ;
END CloseDispose ;
BEGIN
EL.Init(funcList) ;
pi:=3.141592654 ; e:=2.718281828 ;
piL:=3.141592653589793 ; eL:=2.718281828459045 ;
CLOSE
EL.DoForward(funcList,CloseDispose) ;
END Funktionen.